﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DotSpatial.Topology;
using DotSpatial.Data;
using DotSpatial.Controls;
using DotSpatial.Symbology;

namespace HAGISV2
{
    [Serializable]
    public class BarrierLayer:Layer
    {

        public BarrierLayer(string id,HyGrid hygrid,List<int[,]> ibounds,List<int[]> sourceBarrierLocations,FMAPVIEW viewMode,int viewLayerIndex) :
            base(id)
        {
            _gridCoordinates = new List<Coordinate>();
            //_barrierLocationIndexes = new List<int[]>();
            _barrierLocationIndexes = this.BarrierLocationTranslate(sourceBarrierLocations);
            /////测试代码
            //_barrierLocationIndexes.Add(new int[] { 0, 2, 4 });
            //_barrierLocationIndexes.Add(new int[] { 0, 2, 7 });
            //_barrierLocationIndexes.Add(new int[] { 0, 3, 3 });
            //_barrierLocationIndexes.Add(new int[] { 0, 3, 4 });
            //_barrierLocationIndexes.Add(new int[] { 0, 0, 0 });
            

            this._hyGrid = hygrid;
            this.OnSetGrid(_hyGrid.Grid3DCoordinates);
            this.OnSetBoundSigns(GetNeededGridInfo.TranslateList2DTo3D(_hyGrid, ibounds));

            this.BuildDataset();

            this._viewMode = viewMode;
            switch (viewMode)
            {
                case FMAPVIEW.NORMAL:
                    _viewLayerIndex = viewLayerIndex;
                    break;
                case FMAPVIEW.FRONT:
                    _viewFrontIndex = viewLayerIndex;
                    GenerateFrontViewGrid(viewLayerIndex);
                    break;
                case FMAPVIEW.RIGHT:
                    _viewRightIndex = viewLayerIndex;
                    GenerateRightViewGrid(viewLayerIndex);
                    break;
                default:
                    break;
            }

            this.SetLayerData();
        }

        #region 内部方法

        List<int[]> BarrierLocationTranslate(List<int[]> sourceBarrierLocations)
        {
            List<int[]> infoes = new List<int[]>();

            if (sourceBarrierLocations == null)
                return infoes;

            foreach (int[] item in sourceBarrierLocations)
            {
                if (item.Length != 5)
                    throw new Exception("BarrierLocationInfo提供错误！");

                if (item[1] == item[3])
                {
                    if (Math.Abs(item[2] - item[4]) != 1)
                        throw new Exception("BarrierLocationInfo提供错误！");
                    else
                        infoes.Add(new int[] { item[0] - 1, item[1] - 1, Math.Min(item[2], item[4]) * 2 - 1 });
                }
                else if (item[2] == item[4])
                {
                    if (Math.Abs(item[1] - item[3]) != 1)
                        throw new Exception("BarrierLocationInfo提供错误！");
                    else
                        infoes.Add(new int[] { item[0] - 1, Math.Min(item[1], item[3]) - 1, (item[2] - 1) * 2 });
                }
            }

            return infoes;
        }


        bool GenerateFrontViewGrid(int rowIndex)
        {
            //不进行线段生成
            //生成点
            _gridCoordinates.Clear();

            if (_hyGrid.LayersCount <= 0 || _hyGrid.ColsCount <= 0) return false;
            _gridPolygons = new Polygon[_hyGrid.LayersCount, _hyGrid.ColsCount];


            Coordinate helpCoord;
            int row = rowIndex;
            for (int k = 0; k <= _hyGrid.LayersCount; k++)
            {
                for (int i = 0; i <= _hyGrid.ColsCount; i++)
                {
                    helpCoord = HyGrid.Grid3DCoordinates[k, row, i];
                    _gridCoordinates.Add(new Coordinate(helpCoord.X, helpCoord.Z));
                }
            }
            _colCountCell = _hyGrid.ColsCount;
            _rowCountCell = _hyGrid.LayersCount;

            Polygon cellPolygon;

            for (int i = 0; i < _hyGrid.LayersCount; i++)
            {
                for (int j = 0; j < _hyGrid.ColsCount; j++)
                {

                    cellPolygon = GetCellPolygon(i, j);

                    if (cellPolygon == null) return false;

                    _gridPolygons[i, j] = cellPolygon;
                }
            }



            return true;
        }

        bool GenerateRightViewGrid(int colIndex)
        {
            //不进行线段生成
            //生成点
            _gridCoordinates.Clear();

            if (_hyGrid.LayersCount <= 0 || _hyGrid.RowsCount <= 0) return false;
            _gridPolygons = new Polygon[_hyGrid.LayersCount, _hyGrid.RowsCount];

            Coordinate helpCoord;
            for (int k = 0; k <= _hyGrid.LayersCount; k++)
            {
                for (int j = 0; j <= _hyGrid.RowsCount; j++)
                {
                    helpCoord = HyGrid.Grid3DCoordinates[k, j, colIndex];
                    _gridCoordinates.Add(new Coordinate(helpCoord.Y, helpCoord.Z));
                }
            }

            _colCountCell = _hyGrid.RowsCount;
            _rowCountCell = _hyGrid.LayersCount;

            Polygon cellPolygon;

            for (int i = 0; i < _hyGrid.LayersCount; i++)
            {
                for (int j = 0; j < _hyGrid.RowsCount; j++)
                {
                    cellPolygon = GetCellPolygon(i, j);

                    if (cellPolygon == null) return false;

                    _gridPolygons[i, j] = cellPolygon;
                }
            }

            return true;
        }

        /// <summary>
        /// 获取单元格多边形
        /// </summary>
        /// <param name="row"></param>
        /// <param name="col"></param>
        /// <returns></returns>
        Polygon GetCellPolygon(int row, int col)
        {
            if (row < 0 || col < 0 || row >= _rowCountCell || col >= _colCountCell) return null;
            Coordinate[] cellCoordinates = new Coordinate[5];
            try
            {
                cellCoordinates[0] = _gridCoordinates[row * (_colCountCell + 1) + col];
                cellCoordinates[1] = _gridCoordinates[row * (_colCountCell + 1) + col + 1];
                cellCoordinates[2] = _gridCoordinates[(row + 1) * (_colCountCell + 1) + col + 1];
                cellCoordinates[3] = _gridCoordinates[(row + 1) * (_colCountCell + 1) + col];
                cellCoordinates[4] = cellCoordinates[0];
            }
            catch
            {
                return null;
            }

            return new Polygon(new LinearRing(cellCoordinates));
        }

        protected void OnSetBoundSigns(int[, ,] boundary)
        {
            if (boundary == null)
                throw new Exception("BarrierLayer.OnSetBoundery 的参数为无效值！");

            int lenth0 = boundary.GetLength(0);
            int lenth1 = boundary.GetLength(1);
            int lenth2 = boundary.GetLength(2);

            this._iboundSigns = new bool[lenth0, lenth1, lenth2 * 2];

            for (int i = 0; i < lenth0; i++)
            {
                for (int j = 0; j < lenth1; j++)
                {
                    for (int k = 0; k < lenth2; k++)
                    {
                        if (boundary[i, j, k] == 0)
                        {
                            this._iboundSigns[i, j, k * 2] = false;
                            this._iboundSigns[i, j, k * 2 + 1] = false;
                        }
                        else
                        {
                            if (k == lenth2 - 1 || boundary[i, j, k + 1] != 0)
                            {
                                this._iboundSigns[i, j, k * 2 + 1] = true;
                            }
                            if (j == lenth1 - 1 || boundary[i, j + 1, k] != 0)
                            {
                                this._iboundSigns[i, j, k * 2] = true;
                            }
                        }
                    }
                }
            }

            if (this.IsLoaded)
            {
                SetLayerData();
                //(_iLayer as MapPointLayer).DataSet.InitializeVertices();
                //_iLayer.Invalidate();
            }
        }

        /// <summary>
        /// 网格变化时设置更新
        /// </summary>
        /// <param name="coordsZYX"></param>
        protected void OnSetGrid(Coordinate[, ,] coordsZYX)
        {
            int len0 = coordsZYX.GetLength(0) - 1;
            int len1 = coordsZYX.GetLength(1) - 1;
            int len2 = coordsZYX.GetLength(2) - 1;

            this.OnSetFeatureDataSigns();

            this._totalLineFeatures = new LineString[len0, len1, len2 * 2];

            for (int i = 0; i < len0; i++)
            {
                for (int j = 0; j < len1; j++)
                {
                    for (int k = 0; k < len2; k++)
                    {
                        this._totalLineFeatures[i, j, k * 2] = new LineString(new List<Coordinate> { coordsZYX[i, j + 1, k], coordsZYX[i, j + 1, k + 1] });
                        this._totalLineFeatures[i, j, k * 2 + 1] = new LineString(new List<Coordinate> { coordsZYX[i, j, k + 1], coordsZYX[i, j + 1, k + 1] });
                    }
                }
            }
        }

        void SetLayerData()
        {
            if (this._lnFeatureSet.Features.Count > 0) this._lnFeatureSet.Features.Clear();
            if (this._pyFeatureSet.Features.Count > 0) this._pyFeatureSet.Features.Clear();
            
           
            bool[,] addSigns = FeatrueAddSigns;

            int len0 = addSigns.GetLength(0);
            int len1 = addSigns.GetLength(1);

            if (this._viewMode == FMAPVIEW.NORMAL)
            {
                LineString[,] lss = CurrentLayerLineFeatures;

                for (int i = 0; i < len0; i++)
                {
                    for (int j = 0; j < len1; j++)
                    {
                        if (addSigns[i, j])
                        {
                            this._lnFeatureSet.Features.Add(lss[i, j]);
                        }
                    }
                }
            }
            else
            {
                for (int i = 0; i < len0; i++)
                {
                    for (int j = 0; j < len1; j++)
                    {
                        if (addSigns[i, j])
                            this._pyFeatureSet.Features.Add(_gridPolygons[i, j]);
                    }
                }
            }
        }

        void OnSetFeatureDataSigns()
        {
            this._featureDataSigns = new bool[_hyGrid.LayersCount, _hyGrid.RowsCount, _hyGrid.ColsCount*2];

            for (int i = 0; i < _barrierLocationIndexes.Count; i++)
            {
                int[] index = _barrierLocationIndexes[i];
                this._featureDataSigns[index[0], index[1], index[2]] = true;
            }
        }

        #endregion

        #region 公共方法

        public void ResetGridData(HyGrid grid, List<int[,]> boundary)
        {
            int[, ,] bound;

            _hyGrid = grid;
            if (_hyGrid == null)
            {
                return;
            }

            OnSetGrid(_hyGrid.Grid3DCoordinates);

            if (boundary == null || boundary.Count <= 0)
            {
                return;
            }
            else
            {
                bound = GetNeededGridInfo.TranslateList2DTo3D(_hyGrid, boundary);
                OnSetBoundSigns(bound);
            }

            this.Update();
        }

        public override void Redraw()
        {
            #region 生成网格信息并设置有效值
            
            switch (_viewMode)
            {
                case FMAPVIEW.NORMAL:
                    break;
                case FMAPVIEW.FRONT:
                    GenerateFrontViewGrid(ViewLayerIndex);
                    break;
                case FMAPVIEW.RIGHT:
                    GenerateRightViewGrid(ViewLayerIndex);
                    break;
                default:
                    break;

            }

            SetLayerData();

            #endregion

            //刷新视图
            if (_pyLayer != null && _lnLayer != null)
            {
                _pyLayer.DataSet.InitializeVertices();
                _lnLayer.DataSet.InitializeVertices();

                _pyLayer.DataSet.UpdateExtent();
                _lnLayer.DataSet.UpdateExtent();

                _pyLayer.Invalidate();
                _lnLayer.Invalidate();
            }
        }


        ///// <summary>
        ///// 添加单个数据
        ///// </summary>
        ///// <param name="ijk"></param>
        //public void AddPoint(int[] ijk)
        //{

        //}

        ///// <summary>
        ///// 添加多个数据
        ///// </summary>
        ///// <param name="ijks"></param>
        //public void AddPoint(List<int[]> ijks)
        //{
        //    foreach (int[] item in ijks)
        //    {
        //        AddPoint(item);
        //    }
        //}
        ///// <summary>
        ///// 移除单个数据
        ///// </summary>
        ///// <param name="ijk"></param>
        //public void RemovePoint(int[] ijk)
        //{

        //}

        ///// <summary>
        ///// 移除多个数据
        ///// </summary>
        ///// <param name="ijks"></param>
        //public void RemovePoint(List<int[]> ijks)
        //{
        //    foreach (int[] item in ijks)
        //    {
        //        RemovePoint(item);
        //    }

        //}

        ///// <summary>
        ///// 清除数据
        ///// </summary>
        //public void ClearDatas()
        //{
        //    _totalLineFeatures = null;
        //    _featureDataSigns = null;

        //}

        /// <summary>
        /// 设置层表现样式
        /// </summary>
        /// <param name="displayMode">形状</param>
        /// <param name="color"></param>
        /// <param name="size"></param>
        void SetFeatureDisplayStyle()
        {
            if (_pyLayer == null||_lnLayer==null) return;

            _lnLayer.Symbolizer.Strokes[0].SetColor(_color);
            _pyLayer.Symbolizer.Patterns[0].SetFillColor(_color);
            _pyLayer.Symbolizer.Patterns[0].Outline.SetFillColor(_color);
        }

        #endregion

        #region 属性及字段

        bool _displayOptionVisible;
        /// <summary>
        /// 表现选项中设置的可见性
        /// </summary>
        public bool DisplayOptionVisible
        {
            get { return _displayOptionVisible; }
            set
            {
                _displayOptionVisible = value;
                OnSetVisible();
            }
        }

        int _rowCountCell;
        int _colCountCell;

        Polygon[,] _gridPolygons;

        /// 网格坐标点，左上角为0，0 依次向右向下排列
        List<Coordinate> _gridCoordinates;

        
        int _viewLayerIndex = 1;
        int _viewFrontIndex = 1;
        int _viewRightIndex = 1;
        /// <summary>
        /// 索引从1开始
        /// </summary>
        public int ViewLayerIndex
        {
            get
            {
                switch (_viewMode)
                {
                    case FMAPVIEW.NORMAL:
                        return _viewLayerIndex > 1 ? _viewLayerIndex : 1;
                    case FMAPVIEW.FRONT:
                        return _viewFrontIndex > 1 ? _viewFrontIndex : 1;
                    case FMAPVIEW.RIGHT:
                        return _viewRightIndex > 1 ? _viewRightIndex : 1;
                    default:
                        return 1;
                }
            }
            set
            {
                if (value <= 0) return;
                switch (_viewMode)
                {
                    case FMAPVIEW.NORMAL:
                        if (value == _viewLayerIndex||value>_hyGrid.LayersCount) return;
                        _viewLayerIndex = value;

                        break;
                    case FMAPVIEW.FRONT:
                        if (value == _viewFrontIndex||value>_hyGrid.RowsCount) return;
                        _viewFrontIndex = value;
                        break;
                    case FMAPVIEW.RIGHT:
                        if (value == _viewRightIndex||value>_hyGrid.ColsCount) return;
                        _viewRightIndex = value;
                        break;
                    default:
                        return;
                }
                if (this.IsLoaded)
                {
                    this.Redraw();
                }
            }
        }

        /// <summary>
        /// 网格单元有效性
        /// </summary>
        public int[, ,] Boundary
        {
            set
            {
                if (value != null)
                    this.OnSetBoundSigns(value);
            }
        }



        HyGrid _hyGrid;

        public HyGrid HyGrid
        {
            get { return _hyGrid; }
            set 
            { 
                _hyGrid = value;
                if (value != null)
                    OnSetGrid(_hyGrid.Grid3DCoordinates);
                if (this.IsLoaded)
                {
                    this.Redraw();
                }
            }
        }

        List<int[]> _barrierLocationIndexes;
        /// <summary>
        /// 存储障碍物位置信息 存储格式为ZYX 索引从0开始
        /// i为Z方向，j为Y方向，k为X方向，k数量为网格X向列数的两倍
        ///  __|__|__| 
        ///  __|__|__|
        ///  __|__|__| 此例为：层数*4*3网格，则此类中存储数据类型为 层数*4*（3*2）。
        ///  __|__|__|
        /// 索引从1开始。
        /// </summary>
        public List<int[]> BarrierLocationIndexes
        {
            get { return _barrierLocationIndexes; }
            set 
            {
                _barrierLocationIndexes = BarrierLocationTranslate(value);
                OnSetFeatureDataSigns();
            }
        }


        /// <summary>
        /// 以每个单元右下方线两条为标准，
        /// 索引从0开始：偶数表示--方向，奇数表示 | 方向。
        /// 格式与网格中心点对应，Z Y X
        /// 存储数据标志该位置是否有障碍物
        /// </summary>
        bool[, ,] _featureDataSigns;

        /// <summary>
        /// 以每个单元右下方线两条为标准，
        /// 索引从0开始：偶数表示--方向，奇数表示 | 方向。
        /// 格式与网格中心点对应，Z Y X
        /// 存储数据标志该位置是否有效
        /// </summary>
        bool[, ,] _iboundSigns;

        /// <summary>
        /// 以每个单元右下方线两条为标准，
        /// 偶数表示--方向，奇数表示 | 方向。
        /// 格式与网格中心点对应，Z Y X。 
        /// 存储所有线段信息
        /// </summary>
        LineString[, ,] _totalLineFeatures;

        LineString[,] CurrentLayerLineFeatures
        {
            get
            {
                int len0 = _totalLineFeatures.GetLength(1);
                int len1 = _totalLineFeatures.GetLength(2);
                LineString[,] lss = new LineString[len0, len1];

                for (int i = 0; i < len0; i++)
                {
                    for (int j = 0; j < len1; j++)
                    {
                        lss[i, j] = _totalLineFeatures[_viewLayerIndex - 1, i, j];
                    }
                }

                return lss;
            }
        }

        bool[,] FeatrueAddSigns
        {
            get
            {
                bool[,] signs;
                switch (_viewMode)
                {
                    case FMAPVIEW.NORMAL:
                        signs = new bool[_hyGrid.RowsCount, _hyGrid.ColsCount * 2];

                        for (int i = 0; i < _featureDataSigns.GetLength(1); i++)
                        {
                            for (int j = 0; j < _featureDataSigns.GetLength(2); j++)
                            {
                                signs[i, j] = _featureDataSigns[_viewLayerIndex - 1, i, j] && _iboundSigns[_viewLayerIndex - 1, i, j];
                            }
                        }

                        return signs;
                    case FMAPVIEW.FRONT:
                        signs = new bool[_hyGrid.LayersCount, _hyGrid.ColsCount];

                        for (int i = 0; i < _hyGrid.LayersCount; i++)
                        {
                            for (int j = 0; j < _hyGrid.ColsCount; j++)
                            {
                                if (_viewFrontIndex > 1)
                                    signs[i, j] = (_featureDataSigns[i, _viewFrontIndex - 1, j * 2] || _featureDataSigns[i, _viewFrontIndex - 2, j * 2]) && _iboundSigns[i, _viewFrontIndex - 1, j * 2];
                                else
                                    signs[i, j] = _featureDataSigns[i, _viewFrontIndex - 1, j * 2] && _iboundSigns[i, _viewFrontIndex - 1, j * 2];
                            }
                        }

                        return signs;
                    case FMAPVIEW.RIGHT:
                        int yCount = _featureDataSigns.GetLength(1);

                        signs = new bool[_hyGrid.LayersCount, _hyGrid.RowsCount];

                        for (int i = 0; i < _hyGrid.LayersCount; i++)
                        {
                            for (int j = 0; j < _hyGrid.RowsCount; j++)
                            {
                                if (_viewRightIndex > 1)
                                    signs[i, j] = (_featureDataSigns[i,  j , _viewRightIndex * 2 - 1] || _featureDataSigns[i, j, _viewRightIndex * 2 - 3]) && _iboundSigns[i, j, _viewRightIndex * 2 - 1];
                                else
                                    signs[i, j] = _featureDataSigns[i, j, _viewRightIndex * 2 - 1] && _iboundSigns[i, j, _viewRightIndex * 2 - 1];
                            }
                        }

                        return signs;
                    default:
                        break;
                }

                throw new Exception("BarrierLayer.FeatureAddSigns 获取出错！");
            }
        }


        System.Drawing.Color _color;

        public System.Drawing.Color Color
        {
            get { return _color; }
            set
            {
                if (_color == value) return;
                _color = value;
                SetFeatureDisplayStyle();
            }
        }


        [NonSerialized]
        protected FeatureSet _pyFeatureSet;
        [NonSerialized]
        protected FeatureSet _lnFeatureSet;



        [NonSerialized]
        protected MapLineLayer _lnLayer;

        public MapLineLayer LnLayer
        {
            get { return _lnLayer; }
        }


        [NonSerialized]
        protected MapPolygonLayer _pyLayer;

        public MapPolygonLayer PyLayer
        {
            get { return _pyLayer; }
        }

        //public string LayerFileNamePt
        //{
        //    get { return this.DefaultManager.layerPath + this.Id + "_py.shp"; }
        //}

        //public string LayerFileNameLn
        //{
        //    get { return this.DefaultManager.layerPath + this.Id + "_ln.shp"; }
        //}


        #endregion





        #region 保护及私有方法

        protected override void OnSetVisible()
        {
            if (!this.IsLoaded)
            {
                return;

            }
            if (this._visiable == true)
            {
                if (this._viewMode == FMAPVIEW.NORMAL)
                {
                    this._pyLayer.IsVisible = false;
                    this._lnLayer.IsVisible = true;
                }
                else
                {
                    this._pyLayer.IsVisible = true;
                    this._lnLayer.IsVisible = false;
                }
            }
            else
            {
                this._pyLayer.IsVisible = false;
                this._lnLayer.IsVisible = false;
            }
        }

        protected virtual void BuildDataset()
        {
            _pyFeatureSet = new FeatureSet(FeatureType.Polygon);
            
            _lnFeatureSet = new FeatureSet(FeatureType.Line);
        }

        protected override void OnViewModeChanged()
        {
            this.OnSetVisible();
            this.Redraw();
        }

        #endregion

        #region 公共方法

        public override Extent GetLayerExtent()
        {
            if (!this.IsLoaded)
                return null;
            if (this._viewMode == FMAPVIEW.NORMAL)
            {
                if (_lnLayer.DataSet.Features.Count > 0)
                {
                    _lnLayer.DataSet.UpdateExtent();
                    return _lnLayer.Extent;
                }
            }
            else
            {
                if (_pyLayer.DataSet.Features.Count > 0)
                {
                    _pyLayer.DataSet.UpdateExtent();
                    return _pyLayer.Extent;
                }
            }

            return null;
        }

        public override int MapLayerCount
        {
            get
            {
                return 2;
            }
        }

        public override void Render()
        {
            Map map = this.DefaultManager.CurrentMap;
            
            _lnLayer = (MapLineLayer)map.Layers.Add(this._lnFeatureSet);
            _pyLayer = (MapPolygonLayer)map.Layers.Add(this._pyFeatureSet);

            if (this._mapLayerIndex != -1)
            {
                _lnLayer.LockDispose();
                _pyLayer.LockDispose();

                map.Layers.Remove(_pyLayer);
                map.Layers.Remove(_lnLayer);

                map.Layers.Insert(this._mapLayerIndex, _pyLayer);
                map.Layers.Insert(this._mapLayerIndex, _lnLayer);

                _lnLayer.UnlockDispose();
                _pyLayer.UnlockDispose();

                this._mapLayerIndex = -1;
            }


            _lnLayer.SelectionEnabled = false;
            _pyLayer.SelectionEnabled = false;

            _lnLayer.Symbolizer = new LineSymbolizer(this._color, 2);
            _pyLayer.Symbolizer = new PolygonSymbolizer(this._color, this._color);

            this._isLoaded = true;
            OnSetVisible();
        }

        public override void StopRender()
        {
            Map map = this.DefaultManager.CurrentMap;

            map.Layers.Remove(this._pyLayer);
            map.Layers.Remove(this._lnLayer);

            this._isLoaded = false;
        }

        public override bool OpenLayer()
        {
            this.BuildDataset();

            this.Update();

            this.Render();
            this.DefaultManager.CurrentMap.Invalidate();

            return true;
        }

        public override void Select(IEnvelope tolerant, IEnvelope strict, SelectionMode selectionMode)
        {

        }

        public override void ClearSelection()
        {
            if (_pyLayer.Selection.Count > 0)
            {
                this._pyLayer.Selection.Clear();
            }
            if (_lnLayer.Selection.Count > 0)
            {
                this._lnLayer.Selection.Clear();
            }
        }

        #endregion

    }
}
